﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
// 大部分需要写构造，少部分不用
// 少部分需要写析构，大部分不用
//------------------------------------------------------------------------
//析造函数
//C++规定对象在销毁时会⾃动调⽤析构函数，完成对象中资源的清理释放⼯作。
//class Date
//{
//public:
//	// 不写构造，编译生成默认构造
//	//Date()
//	//{
//	//	_year = 1;
//	//	_month = 1;
//	//	_day = 1;
//	//}
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//	
//	~Date()//⽽像Date没有Destroy，其实就是没有资源需要释放，所以严格说Date是不需要析构函数的。
//	{
//		cout << "~Date()" << endl;
//		_year = 0;
//		_month = 0;
//		_day = 0;
//	}
//	void Print()
//	{
//		cout << this->_year << "/" << this->_month << "/" << _day << endl;
//	}
//
//private:
//	// 内置类型
//	int _year;
//	int _month;
//	int _day;
//};
//
//typedef int STDataType;
//class Stack
//{
//public:
//	Stack(int n = 4)
//	{
//		cout << "Stack(int n = 4)" << endl;
//		_a = (STDataType*)malloc(sizeof(STDataType) * n);
//		if (nullptr == _a)
//		{
//			perror("malloc申请空间失败");
//			return;
//		}
//		_capacity = n;
//		_top = 0;
//	}
//	//⼀个类只能有⼀个析构函数。若未显式定义，系统会⾃动⽣成默认的析构函数
//	~Stack()//析构函数名是在类名前加上字符 ~。
//	{
//		cout << "~Stack()" << endl;
//		free(_a);//析构函数的功能类⽐我们之前Stack实现的Destroy功能
//		_a = nullptr;
//		_capacity = _top = 0;
//	}
//private:
//	STDataType* _a;
//	size_t _capacity;
//	size_t _top;
//};
//// 21:15
//// 两个栈实现一个队列
//class Myqueue
//{
//private:
//	// 自定义类型
//	Stack _pushst;
//	Stack _popst;
//};
//
//int main()
//{
//	//如果类中没有申请资源时，析构函数可以不写，直接使⽤编译器⽣成的默认析构函数，如Date
//	Date d1;
//	d1.Print();
//
//	//Date d2(2025);
//	//d2.Print();
//
//	//Date d3(2025, 12);
//	//d3.Print();
//
//	//Date d4(2025, 12, 23);
//	//d4.Print();
//	
//	//当我们不写析构函数时编译器自动生成的析构函数对内置类型成员不做处理，⾃定类型成员会调⽤他的析构函数。
//	Myqueue q;
//	//如果默认⽣成的析构就可以⽤，也就不需要显⽰写析构，如MyQueue；他可以直接调用stack的析构函数，因为stack自定类型成员会调用他的析构函数。
//	// 但是有资源申请时，⼀定要自己写析构，否则会造成资源泄漏，如Stack。
//	Stack st;//对象⽣命周期结束时，系统会⾃动调⽤析构函数。
//
//	return 0;
//	//⼀个局部域的多个对象，C++规定后定义的先析构。即先析构Stack st再Myqueue q最后Date d1
//}


//------------------------------------------------------------------------
// 拷贝构造函数  通常是因为拷贝时涉及到指向空间的问题，防止指向同一块空间就要自己显示写出拷贝构造函数
// 如果⼀个构造函数的第⼀个参数是自身类类型的引⽤，且任何额外的参数都有默认值，则此构造函数也叫做拷⻉构造函数，也就是说拷⻉构造是⼀个特殊的构造函数。

//class Date
//{
//public:
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;
//
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	//Date(const Date& d)//拷贝构造函数   //拷贝构造函数是构造函数的⼀个重载  //如果是Data d会造成无穷调用  //加上const更好
//	//{
//	//	_year = d._year;
//	//	_month = d._month;
//	//	_day = d._day;
//	//}
//
//	//Date(Date* d)//单纯的构造函数的重载，因为引用的底层本来就是指针，这里说单纯的构造主要体现在传参的过程中
//	//{
//	//	_year = d->_year;
//	//	_month = d->_month;
//	//	_day = d->_day;
//	//}
//
//	~Date()
//	{
//		cout << "~Date()" << endl;
//		_year = 0;
//		_month = 0;
//		_day = 0;
//	}
//
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//
typedef int STDataType;
class Stack
{
public:
	Stack(int n = 4)
	{
		cout << "Stack(int n = 4)" << endl;
		_a = (STDataType*)malloc(sizeof(STDataType) * n);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}

	// st2(st1)
	Stack(const Stack& s)//拷贝构造函数
	{
		cout << "Stack(Stack& s)" << endl;
		_a = (STDataType*)malloc(sizeof(STDataType) * s._capacity);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败");
			return;
		}

		memcpy(_a, s._a, sizeof(STDataType) * s._top);
		_top = s._top;
		_capacity = s._capacity;
	}

	void Push(const STDataType& x)
	{
		// 扩容逻辑没写
		_a[_top] = x;
		_top++;
	}

	int Top()
	{
		return _a[_top-1];
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
		free(_a);
		_a = nullptr;
		_top = _capacity = 0;
	}
private:
	STDataType* _a;
	size_t _capacity;
	size_t _top;
};
//
//class MyQueue
//{
//private:
//	Stack _pushst;
//	Stack _popst;
//};
//
//void func(Date d)
//{
//
//}
//
////int main()
////{
////	Date d1(2025, 4, 24);  // 构造
////	Date d2(d1);           // 拷贝构造（当没有显式写出拷贝构造函数时，⾃动⽣成的拷贝构造对内置类型成员变量会完成值拷贝 / 浅拷贝(⼀个字节⼀个字节的拷贝)）
////	Date d4 = d1;          // 拷贝构造
////
////
////	//Date d3(&d1);		   // 构造
////	//Date d5 = &d1;	   // 构造
////
////
////	func(d1);//当你调用函数时要先传值传参，传值传参的时候先调用拷贝构造函数即 Data d = d1 (也就是 Date d(d1) )，调用完继续传值传参，执行函数流程,最后函数栈帧销毁 对类类型的成员执行析构函数
////
////	return 0;
////}
//
////int main()
////{
////	Stack st1;
////	st1.Push(1);
////	st1.Push(2);
////	st1.Push(3);
////	st1.Push(4);
////	//这里如果不写拷贝构造函数，那么编译器就会自动生成拷贝函数完成值拷贝（一个字节一个字节的拷贝）,但是这对于栈来说是致命的，虽然两个对象的空间不一样，但是里面的内容一模一样，这问题就出现在内容一模一样。
////	// 因为栈的底层是动态开辟的数组，如果直接拷贝数组地址，那么两个对象里的指针就会指向同一个空间，那么你对st2做修改,同样会影响到st1。而且main函数结束时，调用stack的析造函数，那么对于那个同一块空间就会被释放两次
////	Stack st2(st1);//一般有析构函数的都有拷贝构造函数
////	
////	Date d1(2025, 4, 24);
////	Date d2(d1);
////
////	MyQueue q1;
////	MyQueue q2(q1);//像MyQueue这样的类型内部主要是⾃定义类型Stack成员，编译器⾃动⽣成的拷⻉构造会调⽤Stack的拷⻉构造，也不需要我们显式实现MyQueue的拷⻉构造。
////	// MyQueue⾃动⽣成的拷⻉构造，会⾃动调⽤Stack拷⻉构造完成pushst/popst的拷⻉，只要Stack拷⻉构造⾃⼰实现了深拷⻉，他就没问题
////	return 0;
////}


//int& f1()//会造成野引用
//int*& f1()
//{
//	int ret = 4;
//	int* a = &ret;
//	return a;//对内置类型，虽然造成了野引用，可以正常运行，但是不推荐
//}

//int& f1()
//{
//	int ret = 4;
//	return ret;//对内置类型，虽然造成了野引用，可以正常运行，但是不推荐
//}

int f1()
{
	int ret = 4;
	return ret;//传值返回，正确写法
}

//Stack& f2()
//Stack& f2()
//{
//	static Stack st;//静态区，出了函数就不会被销毁
//	st.Push(1);
//	st.Push(2);
//	st.Push(3);
//	st.Push(4);
//
//	return st;
//}
//Stack f2()
//{
//	Stack st;//传值返回
//	st.Push(1);
//	st.Push(2);
//	st.Push(3);
//	st.Push(4);
//
//	return st;
//}
//int main()
//{
//	cout << f1() << endl;
//
//	cout << f2().Top() << endl;
//	/*传值返回会产⽣⼀个临时对象调⽤拷⻉构造，传值引⽤返回，返回的是返回对象的别名(引⽤)，没
//	有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象，函数结束就销毁了，那么使⽤
//	引⽤返回是有问题的，这时的引⽤相当于⼀个野引⽤，类似⼀个野指针⼀样。传引⽤返回可以减少
//	拷⻉，但是⼀定要确保返回对象，在当前函数结束后还在，才能⽤引⽤返回。*/
//
//	return 0;
//}
//------------------------------------------------
//运算符重载

//class Date
//{
//public:
//	Date(int year = 1, int month = 1, int day = 1)
//	{
//		cout << "Date(int year = 1, int month = 1, int day = 1)" << endl;
//
//		_year = year;
//		_month = month;
//		_day = day;
//	}
//
//	bool operator==(const Date& a)//如果⼀个重载运算符函数是成员函数，则它的第⼀个运算对象默认传给隐式的this指针，因此运算符重载作为成员函数时，参数⽐运算对象少⼀个。
//	{
//		return _year == a._year
//			&& _month == a._month
//			&& _day == a._day;
//	}
//
//	 //有意义
//	int operator-(const Date& d)
//	{
//
//	}
//
//	 //语法上可以
//	 //但是实践上没意义
//	int operator+(const Date& d)
//	{
//
//	}
//
//	 //有意义
//	Date operator+(int day)
//	{
//
//	}
//
//private:
//	int _year;
//	int _month;
//	int _day;
//};
//// 1、成员放公有（有点憨）
//// 2、提供Getxxx函数（Java喜欢这么搞）
//// 3、友元函数（暂且不推荐）
//// 4、直接放到类里面，实现重载（最爽的）
//bool operator==(const Date& a1, const Date& a2)//引用可以减少拷贝，比直接传值传参要好
//{
//	return a1._year == a2._year//这里成员变量若是private就会报错，解决办法如上
//		&& a1._month == a2._month
//		&& a1._day == a2._day;
//}

//重载操作符⾄少有⼀个类类型参数，不能通过运算符重载改变内置类型对象的含义
//int operator+(int x, int y)//编译报错 //因为没必要对内置类型做运算符重载
//{
//
//}

//int main()
//{
//	Date d1(2025, 4, 27);
//	Date d2(2025, 4, 27);
//	d1 == d2;
//	cout << (d1 == d2) << endl;
//	//operator==(d1, d2);//上下一个意思
//	return 0;
//}

//---------讲讲函数指针
//class A
//{
//public:
//	void func()
//	{
//		cout << "A::func()" << endl;
//	}
//};
//
//typedef void(A::*PF)();
//
//int main()
//{
//
//	PF pf = &A::func;// C++规定成员函数要加&才能取到函数指针
//	A obj;
//	(obj.*pf)();//对象调⽤成员函数指针时，使⽤.*运算符
//	return 0;
//}

//class A
//{
//public:
//	void func()
//	{
//		cout << "A::func()" << endl;
//	}
//};
//
//void f()
//{
//	cout << "f()" << endl;
//}
//
//int main()
//{
//	void(*func1)() = f;
//	func1();
//	(*func1)();//这个逻辑上优于上面那个
//
//	void(A::*pf)() = &A::func;
//	
//	A a;
//	//成员函数调用
//	(a.*pf)();//.*  ::  sizeof  ?:  . 注意以上5个运算符不能重载
//
//  Date d3(2025, 4, 25);
//	Date d4(2025, 4, 26);
//	cout << (d3 == d4) << endl;
//	cout << d3.operator==(d4) << endl;
//	
//	return 0;
//}

/////////////////////////////////////

#include"Date.h"

//----
//赋值运算重载（默认成员函数） 没有显式的写，编译器会自动生成，默认赋值运算符重载⾏为跟默认拷⻉构造函数类似，对内置类型成员变量会完成值拷⻉ / 浅拷⻉(⼀个字节⼀个字节的拷⻉)，对⾃定义类型成员变量会调⽤他的赋值重载函数。
//int main()
//{
//	Date d1(2024, 4, 26);
//	// 拷贝构造，一个已经存在的对象去初始化另一个要实例化的对象
//	//Date d2(d1);
//	Date d2 = d1;
//	//Date d5(d1 + 100);
//	//Date d5 = d1 + 100;
//
//	Date d3(2025, 4, 28);
//
//	// 已经存在的两个对象之间的拷贝
//	//d1 = d3;
//	//d1.operator=(d3);
//	d1 = d2 = d3;
//
//	return 0;
//}

//-----
//Date 测试
//int main()
//{
//	Date d1(2025, 4, 28);
//	Date d2=d1 + 100;
//	cout << "d1: " ;
//	d1.Print();
//	cout << "d2 = d1 + 100: ";
//	d2.Print();
//
//	d1 += 101;
//	//d1.operator+=(101);
//	cout << "d1 = d1 + 101: ";
//	d1.Print();//d1已经被修改了
//	cout << "d2 = d1 + 2: ";
//	d2=d1.operator+(2);//2025.4.28+103day
//	d2.Print();
//	cout<<(d1 == d2)<<endl;
//	cout<<d1.operator==(d2) << endl;//上下一个意思
//
//	Date d3(2005, 10, 20);
//	Date d4(2025, 4, 28);
//	d1= d4 = d3;
//	cout<<"d4 - d3 =" << d4.operator-(d3) << endl;
//	d1.Print();
//
//	//Date d5=d4.operator-(28);
//	d4 -= 365;
//	cout << "d4 = d4 - 365: ";
//	d4.Print();
//}

//void TestDate1()
//{
//	Date d1(2025, 4, 24);
//	//Date d2(d1 + 100);
//	Date d2 = d1 + 100;//d1.operator+(100);
//	d1.Print();
//	d2.Print();
//
//	Date d3 = d1 += 100;
//	d1.Print();
//	d3.Print();
//}

//void TestDate2()
//{
//	Date d1(2025, 4, 26);
//	Date d2 = d1 -= -10000;
//	d1.Print();//2052.9.11
//	d2.Print();
//
//	Date d3(2025, 4, 26);
//	Date d4 = d3 - 10000;
//	d3.Print();
//	d4.Print();
//
//	Date d5(2025, 4, 26);
//	d5 += -100;
//	d5.Print();
//}

//void TestDate3()
//{
//	Date d1(2025, 5, 1);
//	//Date d2 = d1++;
//	Date d2 = d1.operator++(01);//如果是后置++一定要传一个整型，不然就会变成前置++。参数是什么不重要，整型的就行
//	cout << "d2.Print() ";
//	d2.Print();
//	cout << "d1.Print() ";
//	d1.Print();
//
//	Date d3(2025, 5, 20);
//	Date d4 = ++d3;//d3.operator++();
//	cout << "d4.Print() ";
//	d4.Print();
//	cout << "d3.Print() ";
//	d3.Print();
//
//}

//class Seqlist
//{
//public:
//	int& operator[](int i)
//	{
//
//		return _a[i];//引用的妙处，如果不是引用就只是传临时变量，而这具有常性就不能像数组一样修改东西了。
//	}
//	void print(int i)
//	{
//		cout << _a[i] << ' ';
//	}
//private:
//	int _a[10];//顺序表应该是动态开辟内存
//	int _size;
//};

//void TestDate4()
//{
//	Date d1(2025, 5, 1);
//	Date d2(2025, 4, 25);
//	cout << (d1 < d2) << endl;
//	cout << (d1 > d2) << endl;
//	cout << (d1 == d2) << endl;
//	cout << (d1 != d2) << endl;
//
//
//	Date d3(2005, 10, 20);
//	Date d4(2025, 5, 1);
//	cout << d4 - d3 << endl;
//
//}

void TestDate5()
{
	//Date d1(2005, 10, 60);
	//Date d2(2025, 10, 20);
	////d1 << cout;这样写的函数（放在类里面）会导致这样的写法，不利于阅读
	////d1.operator<<(cout);//显式调用

	//cout << d1<<d2;//流插入的运算符重载
	////operator<<(cout, d1);//显式调用
	Date d3;
	cin >> d3;
	cout << d3;
	d3.Print();

	Date d1(2100, 2, 29);
	Date d2(2000, 2, 29);

	// 流插入
	cout << d1 << d2;
	//operator<<(cout, d1);3

	cin >> d1 >> d2;
	cout << d1 << d2;

	cout << d1 - d2 << endl;
}

void TestDate6()
{
	Date d1(2100, 2, 28);
	d1.Print();

	d1 + 100;
	d1 += 100;

	const Date d2(2100, 2, 28);
	d2.Print();

	cout<<(d2 + 100);
	// d2 += 100; //不支持改变对象的语句,因为d2是const

	cout << &d1 << endl;
	cout << &d2 << endl;
}

int main()
{
	//TestDate1();
	//TestDate2();
	//TestDate3();
	//TestDate4();
	TestDate5();
	//TestDate6();

	//Seqlist s;
	//for (int i = 0; i < 10; i++)
	//{
	//	s[i] = i;
	//}
	//for (int i = 0; i < 10; i++)
	//{
	//	s.print(i);
	//}
	//cout << endl;
	return 0;
}

